﻿namespace ch05.binary.interpreter
{
    public static partial class Instr
    {
        private static InstrFn[] InstrTable;

        internal static InstrFn[] GetInstrFn()
        {
            if (InstrTable != null) return InstrTable;
            InstrTable = new InstrFn[256];
            Init();

            return InstrTable;
        }

        private static void Init()
        {
            InstrTable[OpCodes.Call] = Call; // hack!
            InstrTable[OpCodes.Drop] = Drop;
            InstrTable[OpCodes.Select] = Select;
            InstrTable[OpCodes.I32Const] = I32Const;
            InstrTable[OpCodes.I64Const] = I64Const;
            InstrTable[OpCodes.F32Const] = f32Const;
            InstrTable[OpCodes.F64Const] = f64Const;
            InstrTable[OpCodes.I32Eqz] = i32Eqz;
            InstrTable[OpCodes.I32Eq] = i32Eq;
            InstrTable[OpCodes.I32Ne] = i32Ne;
            InstrTable[OpCodes.I32LtS] = i32LtS;
            InstrTable[OpCodes.I32LtU] = i32LtU;
            InstrTable[OpCodes.I32GtS] = i32GtS;
            InstrTable[OpCodes.I32GtU] = i32GtU;
            InstrTable[OpCodes.I32LeS] = i32LeS;
            InstrTable[OpCodes.I32LeU] = i32LeU;
            InstrTable[OpCodes.I32GeS] = i32GeS;
            InstrTable[OpCodes.I32GeU] = i32GeU;
            InstrTable[OpCodes.I64Eqz] = i64Eqz;
            InstrTable[OpCodes.I64Eq] = i64Eq;
            InstrTable[OpCodes.I64Ne] = i64Ne;
            InstrTable[OpCodes.I64LtS] = I64LtS;
            InstrTable[OpCodes.I64LtU] = i64LtU;
            InstrTable[OpCodes.I64GtS] = i64GtS;
            InstrTable[OpCodes.I64GtU] = i64GtU;
            InstrTable[OpCodes.I64LeS] = i64LeS;
            InstrTable[OpCodes.I64LeU] = i64LeU;
            InstrTable[OpCodes.I64GeS] = i64GeS;
            InstrTable[OpCodes.I64GeU] = i64GeU;
            InstrTable[OpCodes.F32Eq] = f32Eq;
            InstrTable[OpCodes.F32Ne] = f32Ne;
            InstrTable[OpCodes.F32Lt] = f32Lt;
            InstrTable[OpCodes.F32Gt] = f32Gt;
            InstrTable[OpCodes.F32Le] = f32Le;
            InstrTable[OpCodes.F32Ge] = f32Ge;
            InstrTable[OpCodes.F64Eq] = f64Eq;
            InstrTable[OpCodes.F64Ne] = f64Ne;
            InstrTable[OpCodes.F64Lt] = f64Lt;
            InstrTable[OpCodes.F64Gt] = f64Gt;
            InstrTable[OpCodes.F64Le] = f64Le;
            InstrTable[OpCodes.F64Ge] = f64Ge;
            InstrTable[OpCodes.I32Clz] = i32Clz;
            InstrTable[OpCodes.I32Ctz] = i32Ctz;
            InstrTable[OpCodes.I32PopCnt] = i32PopCnt;
            InstrTable[OpCodes.I32Add] = i32Add;
            InstrTable[OpCodes.I32Sub] = i32Sub;
            InstrTable[OpCodes.I32Mul] = i32Mul;
            InstrTable[OpCodes.I32DivS] = i32DivS;
            InstrTable[OpCodes.I32DivU] = i32DivU;
            InstrTable[OpCodes.I32RemS] = i32RemS;
            InstrTable[OpCodes.I32RemU] = i32RemU;
            InstrTable[OpCodes.I32And] = i32And;
            InstrTable[OpCodes.I32Or] = i32Or;
            InstrTable[OpCodes.I32Xor] = i32Xor;
            InstrTable[OpCodes.I32Shl] = i32Shl;
            InstrTable[OpCodes.I32ShrS] = i32ShrS;
            InstrTable[OpCodes.I32ShrU] = i32ShrU;
            InstrTable[OpCodes.I32Rotl] = i32Rotl;
            InstrTable[OpCodes.I32Rotr] = i32Rotr;
            InstrTable[OpCodes.I64Clz] = i64Clz;
            InstrTable[OpCodes.I64Ctz] = i64Ctz;
            InstrTable[OpCodes.I64PopCnt] = i64PopCnt;
            InstrTable[OpCodes.I64Add] = i64Add;
            InstrTable[OpCodes.I64Sub] = i64Sub;
            InstrTable[OpCodes.I64Mul] = i64Mul;
            InstrTable[OpCodes.I64DivS] = i64DivS;
            InstrTable[OpCodes.I64DivU] = i64DivU;
            InstrTable[OpCodes.I64RemS] = i64RemS;
            InstrTable[OpCodes.I64RemU] = i64RemU;
            InstrTable[OpCodes.I64And] = i64And;
            InstrTable[OpCodes.I64Or] = i64Or;
            InstrTable[OpCodes.I64Xor] = i64Xor;
            InstrTable[OpCodes.I64Shl] = i64Shl;
            InstrTable[OpCodes.I64ShrS] = i64ShrS;
            InstrTable[OpCodes.I64ShrU] = i64ShrU;
            InstrTable[OpCodes.I64Rotl] = i64Rotl;
            InstrTable[OpCodes.I64Rotr] = i64Rotr;
            InstrTable[OpCodes.F32Abs] = f32Abs;
            InstrTable[OpCodes.F32Neg] = f32Neg;
            InstrTable[OpCodes.F32Ceil] = f32Ceil;
            InstrTable[OpCodes.F32Floor] = f32Floor;
            InstrTable[OpCodes.F32Trunc] = f32Trunc;
            InstrTable[OpCodes.F32Nearest] = f32Nearest;
            InstrTable[OpCodes.F32Sqrt] = f32Sqrt;
            InstrTable[OpCodes.F32Add] = f32Add;
            InstrTable[OpCodes.F32Sub] = f32Sub;
            InstrTable[OpCodes.F32Mul] = f32Mul;
            InstrTable[OpCodes.F32Div] = f32Div;
            InstrTable[OpCodes.F32Min] = f32Min;
            InstrTable[OpCodes.F32Max] = f32Max;
            InstrTable[OpCodes.F32CopySign] = f32CopySign;
            InstrTable[OpCodes.F64Abs] = f64Abs;
            InstrTable[OpCodes.F64Neg] = f64Neg;
            InstrTable[OpCodes.F64Ceil] = f64Ceil;
            InstrTable[OpCodes.F64Floor] = f64Floor;
            InstrTable[OpCodes.F64Trunc] = f64Trunc;
            InstrTable[OpCodes.F64Nearest] = f64Nearest;
            InstrTable[OpCodes.F64Sqrt] = f64Sqrt;
            InstrTable[OpCodes.F64Add] = f64Add;
            InstrTable[OpCodes.F64Sub] = f64Sub;
            InstrTable[OpCodes.F64Mul] = f64Mul;
            InstrTable[OpCodes.F64Div] = f64Div;
            InstrTable[OpCodes.F64Min] = f64Min;
            InstrTable[OpCodes.F64Max] = f64Max;
            InstrTable[OpCodes.F64CopySign] = f64CopySign;
            InstrTable[OpCodes.I32WrapI64] = i32WrapI64;
            InstrTable[OpCodes.I32TruncF32S] = i32TruncF32S;
            InstrTable[OpCodes.I32TruncF32U] = i32TruncF32U;
            InstrTable[OpCodes.I32TruncF64S] = i32TruncF64S;
            InstrTable[OpCodes.I32TruncF64U] = i32TruncF64U;
            InstrTable[OpCodes.I64ExtendI32S] = i64ExtendI32S;
            InstrTable[OpCodes.I64ExtendI32U] = i64ExtendI32U;
            InstrTable[OpCodes.I64TruncF32S] = i64TruncF32S;
            InstrTable[OpCodes.I64TruncF32U] = i64TruncF32U;
            InstrTable[OpCodes.I64TruncF64S] = i64TruncF64S;
            InstrTable[OpCodes.I64TruncF64U] = i64TruncF64U;
            InstrTable[OpCodes.F32ConvertI32S] = F32ConvertI32S;
            InstrTable[OpCodes.F32ConvertI32U] = f32ConvertI32U;
            InstrTable[OpCodes.F32ConvertI64S] = f32ConvertI64S;
            InstrTable[OpCodes.F32ConvertI64U] = f32ConvertI64U;
            InstrTable[OpCodes.F32DemoteF64] = f32DemoteF64;
            InstrTable[OpCodes.F64ConvertI32S] = f64ConvertI32S;
            InstrTable[OpCodes.F64ConvertI32U] = f64ConvertI32U;
            InstrTable[OpCodes.F64ConvertI64S] = f64ConvertI64S;
            InstrTable[OpCodes.F64ConvertI64U] = f64ConvertI64U;
            InstrTable[OpCodes.F64PromoteF32] = f64PromoteF32;
            InstrTable[OpCodes.I32ReinterpretF32] = i32ReinterpretF32;
            InstrTable[OpCodes.I64ReinterpretF64] = i64ReinterpretF64;
            InstrTable[OpCodes.F32ReinterpretI32] = f32ReinterpretI32;
            InstrTable[OpCodes.F64ReinterpretI64] = f64ReinterpretI64;
            InstrTable[OpCodes.I32Extend8S] = i32Extend8S;
            InstrTable[OpCodes.I32Extend16S] = i32Extend16S;
            InstrTable[OpCodes.I64Extend8S] = i64Extend8S;
            InstrTable[OpCodes.I64Extend16S] = i64Extend16S;
            InstrTable[OpCodes.I64Extend32S] = i64Extend32S;
            InstrTable[OpCodes.TruncSat] = truncSat;
        }
    }
}